package com.ibm.cloud.banking.account.component;


import com.ibm.cloud.banking.account.convert.AccountLimitAmtTxSumConvert;
import com.ibm.cloud.banking.account.entity.*;
import com.ibm.cloud.banking.account.repository.AccountLimitAmtTxSumMapper;
import com.ibm.cloud.banking.account.repository.IAccountInfoMapper;
import com.ibm.cloud.banking.account.repository.IAccountOpenCloseDetailMapper;
import com.ibm.cloud.banking.account.repository.IAccountTransDetailMapper;
import com.ibm.cloud.banking.constant.TransErrorMgt;
import com.ibm.cloud.banking.facade.account.dto.AccountBalanceUpdateDTO;
import com.ibm.cloud.banking.facade.account.dto.AccountInfoDTO;
import com.ibm.cloud.banking.facade.account.dto.AccountLimitAmtTxSumDTO;
import com.ibm.cloud.banking.facade.customer.dto.CustAcctRelDTO;
import com.ibm.cloud.banking.platform.exception.BusinessException;
import com.ibm.cloud.banking.utils.ValueCopyUtils;

import io.netty.util.internal.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

@Component
public class AccountBasisComponent {
    static final Logger logger = LoggerFactory.getLogger(AccountBasisComponent.class);

    static final String ACCOUNT_NO_TEMPLATE="accountNo";

    @Autowired
    private IAccountInfoMapper accountInfoMapper;

    @Autowired
    private IAccountOpenCloseDetailMapper accountOpenCloseDetailMapper;

    @Autowired
    private IAccountTransDetailMapper accountTransDetailMapper;

    @Autowired
    private AccountLimitAmtTxSumMapper accountLimitAmtTxSumMapper;

    @Resource
    private AccountLimitAmtTxSumConvert accountLimitAmtTxSumConvert;

//    @Autowired
//    SequenceGenerator sequenceGenerator;

//    @Autowired
//    TellerQueryService teller;

//    public AccountInfoDomainService(StringRedisTemplate redis, String queueName) {
//        super(redis, queueName);
//    }
//
//
//    @Override
//    public void applyJournal(String s, String s1, BigDecimal bigDecimal) {
//
//    }
//
//    @Override
//    public BigDecimal overLimitCallback(String s) {
//        return null;
//    }
//
//    @Override
//    public void recoverCallback(String s) {
//
//    }

    /**
     * 检查同客户同类账号同一产品有效账户的信息
     * @param custAcctRels 同客户同类账户同一产品所有账号列表
     * @return 同客户同类账号同一产品有效账户的信息
     */
    public List<AccountInfo> checkAccountStatus(List<CustAcctRelDTO> custAcctRels) {

        if(custAcctRels==null||custAcctRels.size()==0){
            return null;
        }else{
            List<String> acctNos = new ArrayList<>();
            custAcctRels.forEach(item -> acctNos.add(item.getAccountNo()));

            return accountInfoMapper.getCustEffectiveAccts(custAcctRels.get(0).getCustomerNo(),
                    custAcctRels.get(0).getAccountCategory(),custAcctRels.get(0).getProductNo(),
                    acctNos);
        }
    }


    public int updateAccountBalance(AccountBalanceUpdateDTO paramsDto, Boolean isRefund){

        if(isRefund){
            // 事務補償，金額回退，同時刪除交易記錄
            AccountTransDetail transDetail = accountTransDetailMapper.getByTansNoAndAcctNo(paramsDto.getTransNo(),paramsDto.getAccountNo());
            // 正向交易余额更新和记录交易在同一事务中，只有存在交易明细的情况下，回退原正向余额更新，否则不更新
           if(transDetail != null) {
               // 查询更新前的记录并加锁
               AccountInfo accountInfo = accountInfoMapper.getByAccountNo(paramsDto.getAccountNo());
               accountInfoMapper.updateBalanceByAcctNo(accountInfo.getAccountNo(),paramsDto.getTransAmount());
               logger.info("账号：{}，交易发生额：{}，交易流水：{}，发起自动事务补偿处理。", paramsDto.getAccountNo(),
                       paramsDto.getTransAmount(), paramsDto.getTransNo());
               return accountTransDetailMapper.deleteByTansNoAndAcctNo(paramsDto.getTransNo(),paramsDto.getAccountNo());
           }
           return 0;
        }else{
            return this.updateAccountBalance(paramsDto);
        }
    }

    public int updateAccountBalance(AccountBalanceUpdateDTO paramsDto){

        // 查询更新前的记录并加锁
        AccountInfo accountInfo = accountInfoMapper.getByAccountNo(paramsDto.getAccountNo());

        accountInfoMapper.updateBalanceByAcctNo(accountInfo.getAccountNo(),paramsDto.getTransAmount());

        AccountTransDetail transDetail = new AccountTransDetail();
        ValueCopyUtils.beanToBean(paramsDto,transDetail);
        if(paramsDto.isDeposit()){
            transDetail.setDcFlag(AccountInfo.DC_FLAG_C);
        }else{
            transDetail.setDcFlag(AccountInfo.DC_FLAG_D);
        }

        Date currDate = new Date();
        // todo 高并发下存在潜在的数据问题，再优化
        transDetail.setSequence(getAcctTransDetailNextSeq(paramsDto.getAccountNo()));
        transDetail.setAmount(paramsDto.getTransAmount().abs());
        transDetail.setSystemDate(currDate);
        transDetail.setCreateDt(currDate);
        transDetail.setAccessChannelNo(paramsDto.getInitiationChannelNo());
        if(StringUtils.isEmpty(transDetail.getCurrency())){
            transDetail.setCurrency(AccountInfo.DEFAULT_CURRENCY_RMB);
        }
        // 账户交易明细记录余额更新前的值
        transDetail.setBalance(accountInfo.getBalance());
        logger.info("账号：{}，交易发生额：{}，借贷方向：{}，交易流水：{}",paramsDto.getAccountNo(),
                paramsDto.getTransAmount(),transDetail.getDcFlag(),paramsDto.getTransNo());
        return accountTransDetailMapper.insertSelective(transDetail);

    }

    public int getAcctTransDetailNextSeq(String accountNo){
        return accountTransDetailMapper.getAcctTransDetailNextSeq(accountNo);
    }



    public AccountInfo getByAccountNo(String accountNo) {

        AccountInfo accountInfo = accountInfoMapper.getByAccountNo(accountNo);
        if(accountInfo==null){
            throw new BusinessException(TransErrorMgt.ENTITY_NOT_EXIST.code,
                    String.format(TransErrorMgt.ENTITY_NOT_EXIST.message,"账户信息"));
        }
        return accountInfo;

    }

    public String createAccount(AccountInfoDTO accountInfoDTO) {

        if(accountInfoDTO.getTransAmount().compareTo(new BigDecimal(0))==-1){
            throw new BusinessException(TransErrorMgt.PARAM_VALUE_RANGE_ERROR.code,
                    TransErrorMgt.PARAM_VALUE_RANGE_ERROR.message);
        }

        String branchId=accountInfoDTO.getInitialTellerId().substring(1,6);
//        String branchId=teller.selectById(accountInfoDTO.getInitialTellerId()).getBranchId();

        Map<String,String> template= new HashMap<>(5);
        template.put("branchId", branchId);
        template.put("productNo",accountInfoDTO.getProductNo());
        template.put("accountType",accountInfoDTO.getAccountCategory());
        template.put("id", "");
        template.put("checkCode", ((int)(Math.random() * 9 + 1))+"");
        String accountNo= accountInfoDTO.getAccountNo();//UUID.randomUUID().toString();
        BigDecimal defaultBalance = new BigDecimal(0);
        AccountInfo params = new AccountInfo();
        ValueCopyUtils.beanToBean(accountInfoDTO,params);
        params.setAccountNo(accountNo);
        params.setInitialBranch(branchId);
        params.setName(accountInfoDTO.getCustomerName());
        params.setInitialAmount(accountInfoDTO.getTransAmount());

        if(StringUtil.isNullOrEmpty(params.getCurrency())){
            params.setCurrency(AccountInfo.DEFAULT_CURRENCY_RMB);
        }
        Date initDate = new Date();
        params.setCreateDt(initDate);
        params.setType(AccountInfo.DEFAULT_SETTLEMENT_TYPE);
        params.setStatus(AccountInfo.ACCOUNT_DEFAULT_STATUS);
        params.setControlStatus(AccountInfo.ACCOUNT_CONTROL_STATUS_NORMAL);
        params.setInterestFlag(AccountInfo.INTEREST_FLAG_Y);
        params.setDetailCount(0);
        params.setBalance(defaultBalance);
        params.setOverdraftBalance(defaultBalance);
        params.setAvailableBalance(defaultBalance);
        params.setFreezeBalance(defaultBalance);

        accountInfoMapper.insertSelective(params);

        AccountOpenCloseDetail aocd = new AccountOpenCloseDetail();
        ValueCopyUtils.beanToBean(accountInfoDTO,aocd);
        aocd.setAccountNo(accountNo);
        aocd.setTransType(AccountInfo.ACCOUNT_OPERATION_OPEN);
        aocd.setTransDate(accountInfoDTO.getInitialDate());
        aocd.setSystemDate(initDate);
        aocd.setAccessChannelNo(accountInfoDTO.getInitialChannel());
        aocd.setInitiationChannelNo(accountInfoDTO.getInitialChannel());
        aocd.setTransTellerId(accountInfoDTO.getInitialTellerId());
        aocd.setTransBranch(branchId);

        accountOpenCloseDetailMapper.insertSelective(aocd);

        return accountNo;
    }


    public String createAccount(AccountInfo accountInfoDTO) {

        if(accountInfoDTO.getTransAmount().compareTo(new BigDecimal(0))==-1){
            throw new BusinessException(TransErrorMgt.PARAM_VALUE_RANGE_ERROR.code,
                    TransErrorMgt.PARAM_VALUE_RANGE_ERROR.message);
        }

       // String branchId=teller.selectById(accountInfoDTO.getInitialTellerId()).getBranchId();

        String branchId = "mockBranchId";
        Map<String,String> template= new HashMap<>(5);
        template.put("branchId", branchId);
        template.put("productNo",accountInfoDTO.getProductNo());
        template.put("accountType",accountInfoDTO.getAccountCategory());
        template.put("id", "");
        template.put("checkCode", ((int)(Math.random() * 9 + 1))+"");
        String accountNo = "12345";//TODO 序号生成客户号//sequenceGenerator.generate(ACCOUNT_NO_TEMPLATE, template);
        BigDecimal defaultBalance = new BigDecimal(0);


        accountInfoDTO.setAccountNo(accountNo);
        //params.setInitialBranch(branchId);


        if(StringUtils.isEmpty(accountInfoDTO.getCurrency())){
            accountInfoDTO.setCurrency(AccountInfo.DEFAULT_CURRENCY_RMB);
        }
        Date initDate = new Date();
        accountInfoDTO.setCreateDt(initDate);
        accountInfoDTO.setType(AccountInfo.DEFAULT_SETTLEMENT_TYPE);
        accountInfoDTO.setStatus(AccountInfo.ACCOUNT_DEFAULT_STATUS);
        accountInfoDTO.setControlStatus(AccountInfo.ACCOUNT_CONTROL_STATUS_NORMAL);
        accountInfoDTO.setInterestFlag(AccountInfo.INTEREST_FLAG_Y);
        accountInfoDTO.setDetailCount(0);
        accountInfoDTO.setBalance(defaultBalance);
        accountInfoDTO.setOverdraftBalance(defaultBalance);
        accountInfoDTO.setAvailableBalance(defaultBalance);
        accountInfoDTO.setFreezeBalance(defaultBalance);

        accountInfoMapper.insertSelective(accountInfoDTO);

        AccountOpenCloseDetail aocd = new AccountOpenCloseDetail();
        BeanUtils.copyProperties(accountInfoDTO,aocd);
        aocd.setAccountNo(accountNo);
        aocd.setTransType(AccountInfo.ACCOUNT_OPERATION_OPEN);
        aocd.setTransDate(accountInfoDTO.getInitialDate());
        aocd.setSystemDate(initDate);
      //  aocd.setAccessChannelNo(accountInfoDTO.getInitialChannel());
      //  aocd.setInitiationChannelNo(accountInfoDTO.getInitialChannel());
        aocd.setTransTellerId(accountInfoDTO.getInitialTellerId());
        //aocd.setTransBranch(branchId);

        accountOpenCloseDetailMapper.insertSelective(aocd);

        return accountNo;
    }

    public Integer deleteAccount(String accountNo) {
        return accountInfoMapper.deleteByAccountNo(accountNo);
    }

    public AccountLimitAmtTxSumDTO getAcctDayWithdrawLimit(AccountLimitAmtTxSumDTO accountLimitAmtTxSumDTO) {
        AccountLimitAmtTxSumKey key = new AccountLimitAmtTxSumKey();
        key.setAccountNo(accountLimitAmtTxSumDTO.getAccountNo());
        key.setTransDate(accountLimitAmtTxSumDTO.getTransDate());
        AccountLimitAmtTxSum resust = Optional.ofNullable(accountLimitAmtTxSumMapper.selectByPrimaryKey(key)).orElse(new AccountLimitAmtTxSum());
        return accountLimitAmtTxSumConvert.entityToDto(resust);
    }

    public int updateAcctDayWithdrawLimit(AccountLimitAmtTxSumDTO acctLimitAmitDto) {
        AccountLimitAmtTxSum accountLimitAmtTxSum = accountLimitAmtTxSumConvert.dtoToEntity(acctLimitAmitDto);

        AccountLimitAmtTxSumKey key = new AccountLimitAmtTxSumKey();
        key.setAccountNo(accountLimitAmtTxSum.getAccountNo());
        key.setTransDate(accountLimitAmtTxSum.getTransDate());
        if(accountLimitAmtTxSumMapper.selectByPrimaryKey(key)!=null){
            return accountLimitAmtTxSumMapper.updateByPrimaryKey(accountLimitAmtTxSum);
        }else{
            return accountLimitAmtTxSumMapper.insertSelective(accountLimitAmtTxSum);
        }


    }

//    public List<AccountOpenCloseDetail> getOpenAndCloseAccts(@NotNull String transDate) {
//        Date transDt = DateUtil.parse(transDate,"yyyyMMdd");
//        return accountOpenCloseDetailMapper.getOpenAndCloseAccts(transDt);
//    }
//
//    public List<AccountOpenCloseDetail> getOpenAndCloseAcctsStr(@NotNull String transDate) {
//        return accountOpenCloseDetailMapper.getOpenAndCloseAcctsStr(transDate);
//    }

}